#pragma once
#include <memory>
#include <set>
#include "../common/net.hpp"
#include "../common/message.hpp"

//提供服务注册和发现
//管理服务和主机的映射:进行服务发现,能够告诉客户端哪些主机可以提供服务 hash<method,vector<provider>>
//管理主机发现了哪些服务进行管理:进行服务通知,谁发现过该服务,才进行通知<method,vector<discoverer>>
//哪个连接对应哪个服务提供者进行管理:hash<conn,provider>,连接断开,就可以找到服务提供者进行下线通知
//哪个连接对应哪个服务发现者进行管理:hash<conn,descoverer>,当连接断开,如果有服务上线下线,就不需要进行通知了

namespace rpc
{
    namespace server
    {
        //服务提供者的管理
        class ProviderManager
        {
        public:
            using ptr = std::shared_ptr<ProviderManager>;
            //服务提供者的描述
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                std::mutex _mutex;
                BaseConnection::ptr conn;//链接对象
                Address host;//主机地址信息->外部访问地址
                std::vector<std::string> methods;//服务下线,需要获取提供的服务名称
                Provider(const BaseConnection::ptr & c,const Address & h):
                conn(c),host(h)
                {
                }
                //添加提供的服务
                void appendMethod(const std::string & method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    methods.emplace_back(method);
                }
            };

            //新增服务提供者->当一个新的服务提供者进行注册,进行调用
            void addProvider(const BaseConnection::ptr & c,const Address & h,const std::string & method)
            {
                //查找服务的提供者,找到则获取,找不到则创建
                Provider::ptr provider;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if(it != _conns.end())
                    {
                        provider=it->second;
                    }
                    else//没找到则进行构造
                    {
                        provider = std::make_shared<Provider>(c,h);
                        _conns.insert(std::make_pair(c,provider));
                    }
                    //method方法提供多了一个主机
                    auto & providers = _providers[method];
                    providers.insert(provider);
                }
                provider->appendMethod(method);
            }

            //根据链接对象获取服务提供者->当一个服务提供者断开连接,获取他的信息,用于对服务发现者进行服务下线通知
            Provider::ptr getProvider(const BaseConnection::ptr & c)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if(it != _conns.end())
                {
                    return it->second;
                }
                return Provider::ptr();
            }

            //删除服务提供者->连接断开的时候,才进行删除
            void delProvider(const BaseConnection::ptr & c)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);//找到对应的服务提供者
                if(it == _conns.end())
                {
                    //断开的不是服务提供者
                    return;
                }
                //查看提供了什么服务,从服务提供信息中删除当前服务提供者
                for(auto & method:it->second->methods)//获取该服务提供者提供的方法
                {
                    auto & providers = _providers[method];//获取该方法的所有提供者
                    providers.erase(it->second);//删除该方法的it这个提供者
                }
                _conns.erase(it);//传递迭代器
            }

            //根据服务获取对应的主机
            std::vector<Address> methodHosts(const std::string & method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _providers.find(method);
                if(it == _providers.end())
                {
                    return std::vector<Address>();
                }
                std::vector<Address> result;
                for(auto & provider:it->second)
                {
                    result.push_back(provider->host);
                }
                return result;

            }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string ,std::set<Provider::ptr>> _providers;//方法->提供者
            std::unordered_map<BaseConnection::ptr,Provider::ptr> _conns;//连接->提供者
        };

        //服务发现者的管理
        class DiscovererManager
        {
        public:
            using ptr = std::shared_ptr<DiscovererManager>;
            //服务发现者的描述
            struct Discoverer
            {
                using ptr = std::shared_ptr<Discoverer>;
                std::mutex _mutex;
                BaseConnection::ptr conn;//连接对象->通过连接进行对发现者进行通知
                std::vector<std::string> methods;//发现者发现了哪些方法
                Discoverer(const BaseConnection::ptr & c):conn(c)
                {}
                //添加发现的服务
                void appendMethod(const std::string & method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    methods.push_back(method);
                }
            };

            //新增服务发现者->每次客户端进行服务发现的时候新增发现者,新增服务
            Discoverer::ptr addDiscoverer(const BaseConnection::ptr & c,const std::string & method)
            {
                Discoverer::ptr discoverer;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if(it != _conns.end())
                    {
                        discoverer = it->second;
                    }
                    else
                    {
                        discoverer = std::make_shared<Discoverer>(c);
                        _conns.insert(std::make_pair(c,discoverer));
                    }
                    auto & discoverers = _discoverers[method];
                    discoverers.insert(discoverer);
                }
                discoverer->appendMethod(method);
                return discoverer;
            }

            //删除服务发现者->客户端断开连接的时候进行删除
            void delDiscoverer(const BaseConnection::ptr & c)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if(it == _conns.end())
                {
                    //没有找到链接对应的发现者信息
                    return;
                }
                for(auto & method:it ->second->methods) //遍历发现者发现过的服务
                {
                    auto &discoverers = _discoverers[method];
                    discoverers.erase(it->second);//在该服务中的所有发现者中删除该发现者
                }
                _conns.erase(it);
            }

            //服务上线通知->有新主机上线这个方法,给服务发现者进行通知
            void onlineNotify(const std::string & method,const Address & host)
            {
                return notify(method,host,ServiceOptype::SERVICE_ONLINE);
            }

            //服务下线通知->有主机下线这个方法,给服务发现者进行通知
            void offlienNotify(const std::string & method,const Address & host)
            {
                return notify(method,host,ServiceOptype::SERVICE_OFFLINE);
            }
        private:

            //服务上下线通知
            void notify(const std::string & method,const Address & host,ServiceOptype optype)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _discoverers.find(method);//查找method的所有发现者
                if(it == _discoverers.end())//服务没有调用过->代表该服务当前没有发现者
                {
                    return;
                }
                auto msg_req = MessageFactory::create<ServiceRequest>();//Service的响应
                msg_req->setId(UUID::uuid());
                msg_req->setMType(MType::REQ_SERVICE);
                msg_req->setMethod(method);
                msg_req->setHost(host);
                msg_req->setOptype(optype);
                for(auto & discoverer:it ->second)//遍历发现者
                {
                    discoverer->conn->send(msg_req);//给对应的发现者发送数据
                }
            }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string,std::set<Discoverer::ptr>> _discoverers;//服务关联的发现者
            std::unordered_map<BaseConnection::ptr,Discoverer::ptr> _conns;//一个链接的发现者
        };

        //提供者+发现者的管理
        class PDManager
        {
        public:
            using ptr = std::shared_ptr<PDManager>;
            PDManager():_providers(std::make_shared<ProviderManager>()),
            _discoverers(std::make_shared<DiscovererManager>())
            {}

            //服务注册/服务发现->注册到dispatcher
            void onServiceRequest(const BaseConnection::ptr & conn,const ServiceRequest::ptr & msg)
            {
                //服务注册:新增服务提供者,进行服务上线通知
                //服务发现:新增服务发现者
                ServiceOptype optype = msg->optype();
                if(optype == ServiceOptype::SERVICE_REGISTRY)//服务注册
                {
                    LOG(INFO,"%s:%d 注册服务 %s",msg->host().first.c_str(),msg->host().second,msg->method().c_str());
                    _providers->addProvider(conn,msg->host(),msg->method());//服务添加
                    _discoverers->onlineNotify(msg->method(),msg->host());//上线通知
                    return registryResponse(conn,msg);
                }
                else if(optype == ServiceOptype::SERVICE_DISCOVERY)//服务发现
                {
                    LOG(INFO,"客户端要进行 %s 服务发现",msg->method().c_str());
                    _discoverers->addDiscoverer(conn,msg->method());//添加服务发现
                    return discoveryResponse(conn,msg);
                }
                else
                {
                    LOG(ERROR,"收到服务操作请求,但是操作类型错误");
                    return errorResponse(conn,msg);
                }
            }

            //连接关闭的回调->注册到dispatcher
            void onConnShutdown(const BaseConnection::ptr & conn)//提供者+发现者
            {
                auto provider = _providers->getProvider(conn);
                if(provider.get() != nullptr) //是一个服务提供者
                {
                    LOG(INFO,"%s:%d 服务下线",provider->host.first.c_str(),provider->host.second);
                    for(auto & method:provider->methods)//提供者对应的所有服务
                    {
                        _discoverers->offlienNotify(method,provider->host);//给发现者进行下线通知
                    }
                    _providers->delProvider(conn);//删除对应的提供者

                }
                _discoverers->delDiscoverer(conn);//删除发现者
            }

        private:

            //错误的响应
            void errorResponse(const BaseConnection::ptr & conn,const ServiceRequest::ptr & msg)
            {
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_SERVICE);
                msg_rsp->setRCode(RCode::RCODE_INVALID_OPTYPE);//未知操作类型
                msg_rsp->setOptype(ServiceOptype::SERVICE_UNKNOW);//未知类型
                conn->send(msg_rsp);
            }

            //服务注册响应
            void registryResponse(const BaseConnection::ptr & conn,const ServiceRequest::ptr & msg)
            {
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_SERVICE);//服务响应
                msg_rsp->setRCode(RCode::RCODE_OK);//返回OK
                msg_rsp->setOptype(ServiceOptype::SERVICE_REGISTRY);//关于服务注册的响应
                conn->send(msg_rsp);
            }

            //服务发现响应
            void discoveryResponse(const BaseConnection::ptr & conn,const ServiceRequest::ptr & msg)
            {
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_SERVICE);
                msg_rsp->setOptype(ServiceOptype::SERVICE_DISCOVERY);//服务发现
                std::vector<Address> hosts = _providers->methodHosts(msg->method());//主机地址信息
                if(hosts.empty())
                {
                    msg_rsp->setRCode(RCode::RCODE_NOT_FOUND_SERVICE);//没有找到该服务
                    return conn->send(msg_rsp);
                }
                msg_rsp->setRCode(RCode::RCODE_OK);
                msg_rsp->setMethod(msg->method());
                msg_rsp->setHost(hosts);
                return conn->send(msg_rsp);
            }
        private:
            ProviderManager::ptr _providers;//提供者
            DiscovererManager::ptr _discoverers;//发现者
        };
    }
}